package carassius.DAL;

import carassius.BLL.Events.WaterCondition.WaterConditionAddedListener;
import carassius.BLL.Events.WaterCondition.WaterConditionAddedPublisher;
import carassius.BLL.Events.WaterCondition.WaterConditionRemovedListener;
import carassius.BLL.Events.WaterCondition.WaterConditionRemovedPublisher;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;

/**
 *
 * @author siebz0r
 */
public class WaterConditionTable
		extends Table<WaterConditionRow, String>
		implements WaterConditionAddedPublisher,
				   WaterConditionRemovedPublisher
{
	//<editor-fold defaultstate="collapsed" desc="Fields">
	private final ArrayList<WaterConditionAddedListener> _waterConditionAddedListeners;
	private final ArrayList<WaterConditionRemovedListener> _waterConditionRemovedListeners;
	private final String SQL_ADD = "INSERT INTO water_condition VALUES ( ? , ? )",
			SQL_DELETE = "DELETE FROM water_condition WHERE name = ?",
			SQL_GET_ALL = "SELECT * FROM water_condition",
			SQL_GET_BY_NAME = "SELECT * FROM water_condition WHERE name = ?";
	private boolean _allCached;
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Constructors">
	public WaterConditionTable()
	{
		_waterConditionAddedListeners = new ArrayList<WaterConditionAddedListener>();
		_waterConditionRemovedListeners = new ArrayList<WaterConditionRemovedListener>();
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Public Methods">
	//<editor-fold defaultstate="collapsed" desc="SQL add">
	public WaterConditionRow add(String name, String description) throws SQLException
	{
		name = add(new Object[]
				{
					name, description
				});
		if (name != null)
		{
			return getByPrimaryKey(name);
		}
		return null;
	}

	@Override
	public String add(Object[] args) throws SQLException
	{
		String out = null;
		if (args != null
				&& args.length >= 2
				&& args[0] instanceof String
				&& !((String) args[0]).isEmpty()
				&& args[1] instanceof String
				&& !((String) args[1]).isEmpty())
		{
			out = (String) args[0];
			PreparedStatement st = Database.prepareStatement(SQL_ADD);
			st.setString(1, out);
			st.setString(2, (String) args[1]);

			try
			{
				synchronized (getRows())
				{
					if (st.executeUpdate() == 1)
					{
						_allCached = false;
						WaterConditionRow waterConditionRow = getByPrimaryKey(out);
						_allCached = true;
						fireWaterConditionAdded(waterConditionRow);
					}
					else
					{
						out = null;
					}
				}
			}
			catch (SQLException ex)
			{
				throw ex;
			}
			finally
			{
				st.close();
			}

		}
		return out;
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="SQL delete">
	@Override
	public boolean delete(String name) throws SQLException
	{
		boolean result = false;
		if (name != null
				&& !name.isEmpty())
		{
			synchronized (getRows())
			{
				Database.getWaterMeasurementListTable().deleteByConditionName(name);
				Database.getOptimalOrganismWaterConditionTable().deleteByCondition(name);
				Database.getOptimalAquariumWaterConditionTable().deleteByCondition(name);

				PreparedStatement st = Database.prepareStatement(SQL_DELETE);
				st.setString(1, name);

				WaterConditionRow waterConditionRow = getByPrimaryKey(name);
				if (waterConditionRow != null)
				{
					try
					{
						if (st.executeUpdate() == 1)
						{
							result = true;
							getRows().remove(waterConditionRow.getPrimaryKeys());
							fireWaterConditionRemoved(waterConditionRow);
						}
					}
					catch (SQLException ex)
					{
						throw ex;
					}
					finally
					{
						st.close();
					}
				}
			}
		}
		return result;
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="SQL get">
	@Override
	public Collection<WaterConditionRow> getAll() throws SQLException
	{
		PreparedStatement st = Database.prepareStatement(SQL_GET_ALL);

		synchronized (getRows())
		{
			if (!_allCached)
			{
				try
				{
					ResultSet query = st.executeQuery();

					while (query.next())
					{
						put(new WaterConditionRow(query));
					}
					_allCached = true;
				}
				catch (SQLException ex)
				{
					throw ex;
				}
				finally
				{
					st.close();
				}
			}
			return getRows().values();
		}
	}

	@Override
	public WaterConditionRow getByPrimaryKey(String key) throws SQLException
	{
		WaterConditionRow row = null;
		if (key != null && !key.isEmpty())
		{
			synchronized (getRows())
			{
				row = getRows().get(key);
				if (row != null || _allCached)
				{
					return row;
				}

				PreparedStatement st = Database.prepareStatement(SQL_GET_BY_NAME);
				st.setString(1, key);

				try
				{
					ResultSet query = st.executeQuery();

					if (query.next())
					{
						row = new WaterConditionRow(query);
					}
				}
				catch (SQLException ex)
				{
					throw ex;
				}
				finally
				{
					st.close();
				}
			}
		}
		return row;
	}
	//</editor-fold>
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Events">
	//<editor-fold defaultstate="collapsed" desc="Added">
	@Override
	public void addWaterConditionAddedListener(
			WaterConditionAddedListener listener)
	{
		synchronized (_waterConditionAddedListeners)
		{
			_waterConditionAddedListeners.add(listener);
		}
	}

	@Override
	public void removeWaterConditionAddedListener(
			WaterConditionAddedListener listener)
	{
		synchronized (_waterConditionAddedListeners)
		{
			_waterConditionAddedListeners.remove(listener);
		}
	}

	private void fireWaterConditionAdded(WaterConditionRow row)
	{
		synchronized (_waterConditionAddedListeners)
		{
			for (WaterConditionAddedListener listener : _waterConditionAddedListeners)
			{
				listener.waterConditionAdded(row);
			}
		}
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Removed">
	@Override
	public void addWaterConditionRemovedListener(
			WaterConditionRemovedListener listener)
	{
		synchronized (_waterConditionRemovedListeners)
		{
			_waterConditionRemovedListeners.add(listener);
		}
	}

	@Override
	public void removeWaterConditionRemovedListener(
			WaterConditionRemovedListener listener)
	{
		synchronized (_waterConditionRemovedListeners)
		{
			_waterConditionRemovedListeners.remove(listener);
		}
	}

	private void fireWaterConditionRemoved(WaterConditionRow row)
	{
		synchronized (_waterConditionRemovedListeners)
		{
			for (WaterConditionRemovedListener listener : _waterConditionRemovedListeners)
			{
				listener.waterConditionRemoved(row);
			}
		}
	}
	//</editor-fold>
	//</editor-fold>
}
